#include <Camera.hpp>

bool TCamera::Render(IDK::IRenderState& rndState)
{
	rndState.SetMatrix(IDK::IRenderState::MatrixType::Projection, mProj);
	rndState.SetMatrix(IDK::IRenderState::MatrixType::View, mView);
	return true;
}

void TCamera::Rendered(IDK::IRenderState& /*rndState*/)
{

}

void TCamera::Update()
{
	UpdateHelpers();
}

void TCamera::UpdateHelpers()
{
	mViewProj = mProj*mView;
	mInvViewProj = Math::Inverse(mViewProj);
	mInvView = Math::Inverse(mView);
}

const Math::Ray TCamera::GetRayFromViewport(const Math::Vector2& xy) const
{
	const Math::Vector2 viewport(DefualtDeviceConfig::ScreenWidth, DefualtDeviceConfig::ScreenHeight);

	float nx = (2.0f * (xy.x / viewport.x)) - 1.0f;
	float ny = 1.0f - (2.0f * (xy.y / viewport.y));
	Math::Vector3 nearPoint(nx, ny, -1.f);
	// Use midPoint rather than far point to avoid issues with infinite projection
	Math::Vector3 midPoint (nx, ny, 0.0f);

	// Get ray origin and ray target on near plane in world space
	Math::Vector3 rayOrigin, rayTarget;

	rayOrigin = mInvViewProj * nearPoint;
	rayTarget = mInvViewProj * midPoint;

	Math::Vector3 rayDirection = Math::Normalize(rayTarget - rayOrigin);

	return Math::Ray(rayOrigin, rayDirection);
}

const Math::Vector3 TCamera::GetAbsolutePosition(void) const
{
	const Math::Vector4& col = mInvView[3];
	return Math::Vector3(col.x, col.y, col.z);
}